#include "ResultAnalyzer.h"
#include "HD44780AnalyzerResults.h"
#include <vector>
#include "PluginConstants.h"
#include "LCDCommand.h"

static const char* DISPLAY_MSGS[] =
{
    "Err(Mismatch)",
    "Err(??)",
    "Write(%c)",
    "Write(SPC)",
    "Busy(On)",
    "Busy(Off)",
    "Read(%c)",
    "%s",
    "Write(%c,%c,%c,%c,%c,%c,%c,%c)",
    "Read(%c,%c,%c,%c,%c,%c,%c,%c)",
    "[%s,%s,%s,%s]"
};

static const int MSG_MISMATCH_ERROR  = 0;
static const int MSG_GENERIC_ERROR = 1;
static const int MSG_WRITE = 2;
static const int MSG_WRITE_SPC = 3;
static const int BUSY_FLAG_IS_ON = 4;
static const int BUSY_FLAG_IS_OFF = 5;
static const int MSG_READ = 6;
static const int MSG_GENERIC = 7;
static const int MSG_WRITE_8BITS = 8;
static const int MSG_READ_8BITS = 9;
static const int MSG_CALCULATED = 10;

inline U8 GetDataFromFrame( U64 Data ) { return (U8) ((Data & 0xFF) ); }
inline bool IsBusyFlagOn( U64 Data ) { return ( Data & BUSY_FLAG ) == BUSY_FLAG; }

void GeneratePossibleResults( U8 * possibleBytes, U8 CleanData ) 
{
    for ( int i = 0; i < MAX_POSSIBLE_COMBINATIONS; ++i )
    {
        possibleBytes[i] = (U8)( CleanData | i);
    }
}

U8 GetCommandIndex( U8 Data )
{
    U8 Index = 0;
    while (Data != 0)
    {
        Data = Data >> 1;
        Index++;
    }
    return Index;
}

ResultAnalyzer::ResultAnalyzer()
{
    CreateCommands();
}
ResultAnalyzer::~ResultAnalyzer()
{
    DeleteCommands();
}

void ResultAnalyzer::CreateCommands()
{
    if ( CommandList.size() == 0)
    {
        // 11 & 7 Bits
        CommandList.push_back( new CommandNoop() );
        CommandList.push_back( new CommandClear() );
        CommandList.push_back( new CommandHome() );
        CommandList.push_back( new CommandSetMode() );
        CommandList.push_back( new CommandSetDisplay() );
        CommandList.push_back( new CommandSetCursor() );
        CommandList.push_back( new CommandSetInterface() );
        CommandList.push_back( new CommandSetCGRAM() );
        CommandList.push_back( new CommandSetDDRAM() );

        // 8 Bits
        CommandList.push_back( new CommandNoop8Bits() );
        CommandList.push_back( new CommandClear() );
        CommandList.push_back( new CommandHome() );
        CommandList.push_back( new CommandSetMode() );
        CommandList.push_back( new CommandSetDisplay8Bits() );
        CommandList.push_back( new CommandSetCursor8Bits() );
        CommandList.push_back( new CommandSetInterface8Bits() );
        CommandList.push_back( new CommandSetCGRAM8Bits() );
        CommandList.push_back( new CommandSetDDRAM8Bits() );
    }
}

void ResultAnalyzer::DeleteCommands()
{
    int Size = CommandList.size();
    for ( int i = 0; i < Size; ++i )
    {
        delete CommandList[i];
    }
    CommandList.clear();
}


const char* ErrorRequestAnalyzer::Analyze( Frame& TargetFrame )
{
    return DISPLAY_MSGS[MSG_MISMATCH_ERROR];
}

const char* WriteRequestAnalyzer::Analyze( Frame& TargetFrame )
{
    U8 CleanData = GetDataFromFrame(TargetFrame.mData1);
    if ( SPACE_CHAR == CleanData )
    {
        Buffer =  DISPLAY_MSGS[MSG_WRITE_SPC];
    }
    else
    {
        char TempBuffer[MAX_BUFFER_SIZE];
        sprintf( (char*)&TempBuffer,DISPLAY_MSGS[MSG_WRITE], CleanData);
        Buffer = (char*)&TempBuffer;
    }
    return Buffer.c_str();
}


const char* ReadBusyFlagRequestAnalyzer::Analyze( Frame& TargetFrame )
{
    return IsBusyFlagOn(TargetFrame.mData1) ?  DISPLAY_MSGS[BUSY_FLAG_IS_ON] :  DISPLAY_MSGS[BUSY_FLAG_IS_OFF];
}


const char* ReadDataRequestAnalyzer::Analyze( Frame& TargetFrame )
{
    U8 CleanData = GetDataFromFrame(TargetFrame.mData1);
    char TempBuffer[MAX_BUFFER_SIZE];
    sprintf( (char*)&TempBuffer,DISPLAY_MSGS[MSG_READ], CleanData);
    Buffer = (char*)&TempBuffer;
    return Buffer.c_str();
}


const char* ControlRequestAnalyzer::Analyze( Frame& TargetFrame )
{
    U8 CleanData = GetDataFromFrame(TargetFrame.mData1);
    return CommandList[GetCommandIndex(CleanData)]->GetText(CleanData);
}

const char* ErrorRequestAnalyzer8Bits::Analyze( Frame& TargetFrame )
{
    return DISPLAY_MSGS[MSG_GENERIC_ERROR];
}


const char* WriteRequestAnalyzer8Bits::Analyze( Frame& TargetFrame )
{
    U8 possibleBytes[MAX_POSSIBLE_COMBINATIONS];
    U8 CleanData = GetDataFromFrame(TargetFrame.mData1);
    GeneratePossibleResults(possibleBytes, CleanData);
    char TempBuffer[MAX_BUFFER_SIZE];
    sprintf(TempBuffer,DISPLAY_MSGS[MSG_WRITE_8BITS], possibleBytes[0], possibleBytes[1],possibleBytes[2],
        possibleBytes[3],possibleBytes[4],possibleBytes[5],possibleBytes[6],possibleBytes[7]);
    Buffer = (char*)&TempBuffer;
    return Buffer.c_str();
}


const char* ReadBusyFlagRequestAnalyzer8Bits::Analyze( Frame& TargetFrame )
{
    return IsBusyFlagOn(TargetFrame.mData1) ?  DISPLAY_MSGS[BUSY_FLAG_IS_ON] :  DISPLAY_MSGS[BUSY_FLAG_IS_OFF];
}


const char* ReadDataRequestAnalyzer8Bits::Analyze( Frame& TargetFrame )
{
    U8 possibleBytes[MAX_POSSIBLE_COMBINATIONS];
    U8 CleanData = GetDataFromFrame(TargetFrame.mData1);
    GeneratePossibleResults(possibleBytes, CleanData);
    char TempBuffer[MAX_BUFFER_SIZE];
    sprintf(TempBuffer,DISPLAY_MSGS[MSG_READ_8BITS], possibleBytes[0], possibleBytes[1],possibleBytes[2],
        possibleBytes[3],possibleBytes[4],possibleBytes[5],possibleBytes[6],possibleBytes[7]);
    Buffer = (char*)&TempBuffer;
    return Buffer.c_str();
}


const char* ControlRequestAnalyzer8Bits::Analyze( Frame& TargetFrame )
{
    U8 CleanData = GetDataFromFrame(TargetFrame.mData1);
    Buffer = CommandList[9 + GetCommandIndex(CleanData)]->GetText(CleanData);
    return Buffer.c_str();
}

